Trait Ordination Plant Community Analysis

  1. traits

    1. above- and belowground

      1. height & SLA
    2. acquisitive vs. conservative resource-use strategies

      1. rooting depth
    3. collaborative vs. individual resource-use strategies

      1. fine root proportion

      2. thickness of roots

Goal: Examine how traits shift in community compositional (ordinational) space, placing each trait on an axis.

Author: Caryn D. Iwanaga

Updated: 01/24/2025

Libraries

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.0.2     ── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(dplyr)
library(ggplot2)
library(httr) # read out Dropbox folders
library(vegan)
Loading required package: permute
Loading required package: lattice
This is vegan 2.6-8

Read in Data

cover.dat.labels <- read.csv("https://www.dropbox.com/scl/fi/up8nnzkcpchsr45f8cm92/Compost_Cover_LongClean.csv?rlkey=z2tvaj8t6khadef7ydz782zka&st=qwef9ys0&dl=1") %>%
  mutate(
    nut_trt = factor(ifelse(nut_trt =="C", "+compost", ifelse(nut_trt =="F", "+N fertilizer", ifelse(nut_trt =="N", "control", NA))), levels = c("control", "+N fertilizer", "+compost")),
    ppt_trt = ifelse(ppt_trt == "D", "dry", ifelse(ppt_trt == "XC", "control", ifelse(ppt_trt == "W", "wet", NA))))


# Define a reusable color scale
# custom_colors <- scale_fill_manual(
#   values = c(
#     "control" = rgb(195, 197, 193, maxColorValue = 250),
#     "+N fertilizer" = rgb(87, 62, 92, maxColorValue = 225),
#     "+compost" = rgb(167, 156, 109, maxColorValue = 225)
#   )
# )

custom_colors <- scale_fill_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

# Set a global theme
theme_set(theme_bw())

Make site x species matrix

  1. Calculate relative abundances of species for each site
    1. confused how to aggregate abundances because even grouping by plotid (nut_trt and ppt_trt), year, species, and grazing history (block 1&2 – high, block 3&4 – low) and averaged, the sd are as high as 45.96!
      1. proceeded with these high sd to see what happens (ask Lauren)
site.df <- 
  cover.dat.labels[, c(1:7, 18:19)] %>% #subset columns
  mutate(
    grazing_hist = ifelse(block == 1 | block == 2, "high", ifelse(block == 3 | block == 4, "low", NA))
  ) %>% # separate by block (grazing intensities)
  group_by(nut_trt, ppt_trt, yr, code4, grazing_hist) %>% # make each code unique -- one value for species abundance for each trt
  summarise(
    # pct_cover,
    abundance = mean(pct_cover)
    # sd = sd(pct_cover)
  )
`summarise()` has grouped output by 'nut_trt', 'ppt_trt', 'yr', 'code4'. You can override using the `.groups` argument.
matrix0 <- spread(
  site.df, 
  code4, 
  abundance, 
  fill = 0)

# make rownames ----
rownames(matrix0) <- paste(matrix0$nut_trt, matrix0$ppt_trt, matrix0$yr, matrix0$grazing_hist, sep = "_")
Warning: Setting row names on a tibble is deprecated.
# delete columns ---- 
matrix <- matrix0[, c(5:79)]

# relativize data with Bray-Curtis dissimilarity
matrix.bray <- decostand(matrix, "total")
rownames(matrix.bray) <- rownames(matrix0)

Run NMDS

Rules of thumb:

  • < 0.05 is excellent

  • 0.05-0.1 is good

  • 0.1-0.2 is fair

  • 0.2-0.3 is cause for concern…

  • > 0.3 is poor, random

All years

Stress: fair

0.1966553 

Grouping by year and grazing history had most significant clustering shown.

metaMDS()
nmds.comp <- metaMDS(matrix.bray, k=2, trymax = 25)
Run 0 stress 0.2020736 
Run 1 stress 0.2023246 
... Procrustes: rmse 0.07023633  max resid 0.190107 
Run 2 stress 0.2017185 
... New best solution
... Procrustes: rmse 0.02245434  max resid 0.1414201 
Run 3 stress 0.2088616 
Run 4 stress 0.1970656 
... New best solution
... Procrustes: rmse 0.07244987  max resid 0.2329502 
Run 5 stress 0.2176689 
Run 6 stress 0.1970626 
... New best solution
... Procrustes: rmse 0.006282932  max resid 0.03757378 
Run 7 stress 0.2020248 
Run 8 stress 0.2200448 
Run 9 stress 0.2033604 
Run 10 stress 0.1973254 
... Procrustes: rmse 0.02289426  max resid 0.1158253 
Run 11 stress 0.2042184 
Run 12 stress 0.2020728 
Run 13 stress 0.2017572 
Run 14 stress 0.203447 
Run 15 stress 0.2183276 
Run 16 stress 0.1990614 
Run 17 stress 0.2000129 
Run 18 stress 0.2089696 
Run 19 stress 0.2082397 
Run 20 stress 0.2028091 
Run 21 stress 0.2000005 
Run 22 stress 0.1999666 
Run 23 stress 0.2019172 
Run 24 stress 0.2147543 
Run 25 stress 0.2017483 
*** Best solution was not repeated -- monoMDS stopping criteria:
    25: stress ratio > sratmax
nmds.comp # pretty not great stress

Call:
metaMDS(comm = matrix.bray, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray 
Distance: bray 

Dimensions: 2 
Stress:     0.1970626 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 6 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray’ 
stressplot(nmds.comp)

plot(nmds.comp, type="t")


nmds1 <- as.data.frame(scores(nmds.comp, choices=c(1), display=c("sites"))) %>%
  mutate(matrix0[, c(0:4)])
nmds2 <- as.data.frame(scores(nmds.comp, choices=c(2), display=c("sites")))

nmds_dat <- cbind(nmds1, nmds2) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_dat, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.

ggplot(nmds_dat, aes(NMDS1, NMDS2, color = as.factor(yr), fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Year")


ggplot(nmds_dat, aes(NMDS1, NMDS2, fill = as.factor(ppt_trt), color = as.factor(ppt_trt))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat, aes(NMDS1, NMDS2,  fill = as.factor(grazing_hist), color = as.factor(grazing_hist))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Grazing History")


ggplot(nmds_dat, aes(NMDS1, NMDS2,  color = as.factor(grazing_hist), fill = as.factor(yr))) +
  geom_point(aes(fill = as.factor(yr)), shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "Grouped by Grazing History & Year") +
  scale_color_manual(
  values = c(
    "low" = "cyan",
    "high" = "brown",
  "2019" = "salmon",
  "2020" = "limegreen",
  "2021" = "cornflowerblue")
  )

  
ggplot(nmds_dat, aes(NMDS1, NMDS2, color = nut_trt, fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(nut_trt)),
             geom = "polygon",
             fill = NA,  # Makes the ellipse transparent inside
             size = 1) +
  labs(title = "Grouped by Nutrient Treatment & Year") +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

All years - LOW GRAZING ONLY

Stress: fair

0.1869068

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.low <- matrix0 %>%
  filter(grazing_hist == "low")

row.low <- paste(matrix.low$nut_trt, matrix.low$ppt_trt, matrix.low$yr, matrix.low$grazing_hist, sep = "_")

matrix.low <- matrix.low[, c(5:79)]

rownames(matrix.low) <- row.low
Warning: Setting row names on a tibble is deprecated.
matrix.bray.low <- decostand(matrix.low, "total")

metaMDS()

plot

ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  color = as.factor(yr), shape = nut_trt)) +
  geom_point(size = 3, stroke = 1) + 
  labs(title = "2019-2021 (LOW) - Grouping by Year & Nutrient Treatment")


ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  labs(title = "2019-2021 (LOW) - Grouping by Nutrient Treatment")+ 
  custom_colors



ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2019-2021 (LOW) - Grouping by Precipitation Treatment") 


# add year ellipses ---- 
ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "2019-2021 (LOW) - Grouping by Nutrient Treatment")+ 
  custom_colors



ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
    stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  custom_colors + 
  labs(title = "2019-2021 (LOW) - Grouping by Precipitation Treatment") 

Make each individual year NMDS to see if there’s better stress

2019

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2019 <- matrix0 %>%
  filter(yr == 2019)

row.2019 <- paste(matrix.2019$nut_trt, matrix.2019$ppt_trt, matrix.2019$yr, matrix.2019$grazing_hist, sep = "_")

matrix.2019 <- matrix.2019[, c(5:79)]

rownames(matrix.2019) <- row.2019
Warning: Setting row names on a tibble is deprecated.
matrix.bray.2019 <- decostand(matrix.2019, "total")

nmds 2019

Stress: Excellent

0.0560178
metaMDS()
nmds.2019 <- metaMDS(matrix.bray.2019, k=2, trymax = 25)
Run 0 stress 0.0560178 
Run 1 stress 0.05957995 
Run 2 stress 0.05960972 
Run 3 stress 0.05851815 
Run 4 stress 0.05851812 
Run 5 stress 0.05957995 
Run 6 stress 0.06407773 
Run 7 stress 0.05851805 
Run 8 stress 0.05982901 
Run 9 stress 0.06074817 
Run 10 stress 0.05984339 
Run 11 stress 0.05982901 
Run 12 stress 0.07612032 
Run 13 stress 0.06031567 
Run 14 stress 0.05652852 
Run 15 stress 0.06130516 
Run 16 stress 0.05905532 
Run 17 stress 0.0560178 
... Procrustes: rmse 1.328847e-06  max resid 3.511506e-06 
... Similar to previous best
Run 18 stress 0.07356079 
Run 19 stress 0.05652852 
Run 20 stress 0.05957995 
*** Best solution repeated 1 times
nmds.2019 # pretty not great stress

Call:
metaMDS(comm = matrix.bray.2019, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2019 
Distance: bray 

Dimensions: 2 
Stress:     0.0560178 
Stress type 1, weak ties
Best solution was repeated 1 time in 20 tries
The best solution was from try 0 (metric scaling or null solution)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2019’ 
stressplot(nmds.2019)

plot(nmds.2019, type="t")


nmds1.2019 <- as.data.frame(scores(nmds.2019, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 4)
  )
nmds2.2019 <- as.data.frame(scores(nmds.2019, choices=c(2), display=c("sites")))

nmds_2019_dat <- cbind(nmds1.2019, nmds2.2019) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
# read in trait data

# subset trait data to match comp data

# set matching row names

2020

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2020 <- matrix0 %>%
  filter(yr == 2020)

row.2020 <- paste(matrix.2020$nut_trt, matrix.2020$ppt_trt, matrix.2020$yr, matrix.2020$grazing_hist, sep = "_")

matrix.2020 <- matrix.2020[, c(5:79)]

rownames(matrix.2020) <- row.2020
Warning: Setting row names on a tibble is deprecated.
matrix.bray.2020 <- decostand(matrix.2020, "total")

nmds 2020

Stress: fair

0.1522495
metaMDS()
nmds.2020 <- metaMDS(matrix.bray.2020, k=2, trymax = 25)
Run 0 stress 0.1524241 
Run 1 stress 0.1729906 
Run 2 stress 0.1595535 
Run 3 stress 0.1584809 
Run 4 stress 0.1524241 
... New best solution
... Procrustes: rmse 1.001013e-05  max resid 2.563444e-05 
... Similar to previous best
Run 5 stress 0.1522495 
... New best solution
... Procrustes: rmse 0.02107748  max resid 0.06346541 
Run 6 stress 0.1524241 
... Procrustes: rmse 0.02107671  max resid 0.06351798 
Run 7 stress 0.1522495 
... New best solution
... Procrustes: rmse 6.786807e-06  max resid 1.943279e-05 
... Similar to previous best
Run 8 stress 0.1821737 
Run 9 stress 0.1594876 
Run 10 stress 0.1872714 
Run 11 stress 0.1705568 
Run 12 stress 0.1752228 
Run 13 stress 0.1522045 
... New best solution
... Procrustes: rmse 0.01182953  max resid 0.03730308 
Run 14 stress 0.1747777 
Run 15 stress 0.1592892 
Run 16 stress 0.1595535 
Run 17 stress 0.1625903 
Run 18 stress 0.1594876 
Run 19 stress 0.165848 
Run 20 stress 0.1594877 
Run 21 stress 0.1524241 
... Procrustes: rmse 0.0248137  max resid 0.06599096 
Run 22 stress 0.1584809 
Run 23 stress 0.1522495 
... Procrustes: rmse 0.01183773  max resid 0.03738525 
Run 24 stress 0.1744238 
Run 25 stress 0.1744238 
*** Best solution was not repeated -- monoMDS stopping criteria:
    16: stress ratio > sratmax
     9: scale factor of the gradient < sfgrmin
nmds.2020

Call:
metaMDS(comm = matrix.bray.2020, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2020 
Distance: bray 

Dimensions: 2 
Stress:     0.1522045 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 13 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2020’ 
stressplot(nmds.2020)

plot(nmds.2020, type="t")


nmds1.2020 <- as.data.frame(scores(nmds.2020, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 4)
  )
nmds2.2020 <- as.data.frame(scores(nmds.2020, choices=c(2), display=c("sites")))

nmds_2020_dat <- cbind(nmds1.2020, nmds2.2020) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
  geom_point(size = 4, stroke = 1) + 
  labs(title = "2020 - Grouping by Grazing History & Nutrient Treatment") 


ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2020 - Grouping by Nutrient Treatment")


ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2020 - Grouping by Precipitation Treatment")

2021

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021 <- matrix0 %>%
  filter(yr == 2021)

row.2021 <- paste(matrix.2021$nut_trt, matrix.2021$ppt_trt, matrix.2021$yr, matrix.2021$grazing_hist, sep = "_")

matrix.2021 <- matrix.2021[, c(5:79)]

rownames(matrix.2021) <- row.2021
Warning: Setting row names on a tibble is deprecated.
matrix.bray.2021 <- decostand(matrix.2021, "total")

nmds 2021

Stress: fair

0.1230831
metaMDS()
nmds.2021 <- metaMDS(matrix.bray.2021, k=2, trymax = 25)
Run 0 stress 0.1232098 
Run 1 stress 0.132972 
Run 2 stress 0.132972 
Run 3 stress 0.1506988 
Run 4 stress 0.1515614 
Run 5 stress 0.1232098 
... New best solution
... Procrustes: rmse 1.844754e-06  max resid 4.667063e-06 
... Similar to previous best
Run 6 stress 0.1230832 
... New best solution
... Procrustes: rmse 0.04464562  max resid 0.1321501 
Run 7 stress 0.1232098 
... Procrustes: rmse 0.04464457  max resid 0.1315388 
Run 8 stress 0.1421227 
Run 9 stress 0.1339879 
Run 10 stress 0.1515617 
Run 11 stress 0.1421227 
Run 12 stress 0.1506988 
Run 13 stress 0.132972 
Run 14 stress 0.1555173 
Run 15 stress 0.1436877 
Run 16 stress 0.1761755 
Run 17 stress 0.1339879 
Run 18 stress 0.1232098 
... Procrustes: rmse 0.04464533  max resid 0.1315293 
Run 19 stress 0.1507047 
Run 20 stress 0.1525517 
Run 21 stress 0.1339879 
Run 22 stress 0.1230832 
... Procrustes: rmse 2.173671e-05  max resid 6.138502e-05 
... Similar to previous best
*** Best solution repeated 1 times
nmds.2021

Call:
metaMDS(comm = matrix.bray.2021, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2021 
Distance: bray 

Dimensions: 2 
Stress:     0.1230832 
Stress type 1, weak ties
Best solution was repeated 1 time in 22 tries
The best solution was from try 6 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2021’ 
stressplot(nmds.2021)

plot(nmds.2021, type="t")


nmds1.2021 <- as.data.frame(scores(nmds.2021, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 4)
  )
nmds2.2021 <- as.data.frame(scores(nmds.2021, choices=c(2), display=c("sites")))

nmds_2021_dat <- cbind(nmds1.2021, nmds2.2021) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 - Grouping by Grazing History & Nutrient Treatment")


ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 - Grouping by Nutrient Treatment")


ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 - Grouping by Precipitation Treatment")

Make species x trait matrix

Greenhouse traits

  • height, leaf dry matter content, specific leaf area, root mass fraction, relative growth rate, coarse root diameter, root density, specific root length of fine roots, specific root length of coarse roots

Field traits

  • height, leaf dry matter content, specific leaf area, seed mass, leaf C, leaf N
# read in trait data

# subset trait data to match comp data

# set matching row names

LS0tCnRpdGxlOiAiVHJhaXQgT3JkaW5hdGlvbiBQbGFudCBDb21tdW5pdHkgQW5hbHlzaXMiCmF1dGhvcjogIkNhcnluIEQuIEl3YW5hZ2EiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCi0tLQoKIyBUcmFpdCBPcmRpbmF0aW9uIFBsYW50IENvbW11bml0eSBBbmFseXNpcwoKMS4gIHRyYWl0cwoKICAgIDEuICBhYm92ZS0gYW5kIGJlbG93Z3JvdW5kCgogICAgICAgIDEuICBoZWlnaHQgJiBTTEFcCgogICAgMi4gIGFjcXVpc2l0aXZlIHZzLiBjb25zZXJ2YXRpdmUgcmVzb3VyY2UtdXNlIHN0cmF0ZWdpZXMKCiAgICAgICAgMS4gIHJvb3RpbmcgZGVwdGgKCiAgICAzLiAgY29sbGFib3JhdGl2ZSB2cy4gaW5kaXZpZHVhbCByZXNvdXJjZS11c2Ugc3RyYXRlZ2llcwoKICAgICAgICAxLiAgZmluZSByb290IHByb3BvcnRpb24KCiAgICAgICAgMi4gIHRoaWNrbmVzcyBvZiByb290cwoKW0dvYWxdey51bmRlcmxpbmV9OiBFeGFtaW5lIGhvdyB0cmFpdHMgc2hpZnQgaW4gY29tbXVuaXR5IGNvbXBvc2l0aW9uYWwgKG9yZGluYXRpb25hbCkgc3BhY2UsIHBsYWNpbmcgZWFjaCB0cmFpdCBvbiBhbiBheGlzLgoKQXV0aG9yOiBDYXJ5biBELiBJd2FuYWdhCgpVcGRhdGVkOiAwMS8yNC8yMDI1CgojIyBMaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGh0dHIpICMgcmVhZCBvdXQgRHJvcGJveCBmb2xkZXJzCmxpYnJhcnkodmVnYW4pCmBgYAoKIyMgUmVhZCBpbiBEYXRhCgpgYGB7cn0KY292ZXIuZGF0LmxhYmVscyA8LSByZWFkLmNzdigiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vc2NsL2ZpL3VwOG5uemtjcGNoc3I0NWY4Y205Mi9Db21wb3N0X0NvdmVyX0xvbmdDbGVhbi5jc3Y/cmxrZXk9ejJ0dmFqOHQ2a2hhZGVmN3lkejc4MnprYSZzdD1xd2VmOXlzMCZkbD0xIikgJT4lCiAgbXV0YXRlKAogICAgbnV0X3RydCA9IGZhY3RvcihpZmVsc2UobnV0X3RydCA9PSJDIiwgIitjb21wb3N0IiwgaWZlbHNlKG51dF90cnQgPT0iRiIsICIrTiBmZXJ0aWxpemVyIiwgaWZlbHNlKG51dF90cnQgPT0iTiIsICJjb250cm9sIiwgTkEpKSksIGxldmVscyA9IGMoImNvbnRyb2wiLCAiK04gZmVydGlsaXplciIsICIrY29tcG9zdCIpKSwKICAgIHBwdF90cnQgPSBpZmVsc2UocHB0X3RydCA9PSAiRCIsICJkcnkiLCBpZmVsc2UocHB0X3RydCA9PSAiWEMiLCAiY29udHJvbCIsIGlmZWxzZShwcHRfdHJ0ID09ICJXIiwgIndldCIsIE5BKSkpKQoKCiMgRGVmaW5lIGEgcmV1c2FibGUgY29sb3Igc2NhbGUKIyBjdXN0b21fY29sb3JzIDwtIHNjYWxlX2ZpbGxfbWFudWFsKAojICAgdmFsdWVzID0gYygKIyAgICAgImNvbnRyb2wiID0gcmdiKDE5NSwgMTk3LCAxOTMsIG1heENvbG9yVmFsdWUgPSAyNTApLAojICAgICAiK04gZmVydGlsaXplciIgPSByZ2IoODcsIDYyLCA5MiwgbWF4Q29sb3JWYWx1ZSA9IDIyNSksCiMgICAgICIrY29tcG9zdCIgPSByZ2IoMTY3LCAxNTYsIDEwOSwgbWF4Q29sb3JWYWx1ZSA9IDIyNSkKIyAgICkKIyApCgpjdXN0b21fY29sb3JzIDwtIHNjYWxlX2ZpbGxfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikKCiMgU2V0IGEgZ2xvYmFsIHRoZW1lCnRoZW1lX3NldCh0aGVtZV9idygpKQpgYGAKCiMjIE1ha2Ugc2l0ZSB4IHNwZWNpZXMgbWF0cml4CgoxLiAgQ2FsY3VsYXRlIHJlbGF0aXZlIGFidW5kYW5jZXMgb2Ygc3BlY2llcyBmb3IgZWFjaCBzaXRlCiAgICAxLiAgY29uZnVzZWQgaG93IHRvIGFnZ3JlZ2F0ZSBhYnVuZGFuY2VzIGJlY2F1c2UgZXZlbiBncm91cGluZyBieSBwbG90aWQgKG51dF90cnQgYW5kIHBwdF90cnQpLCB5ZWFyLCBzcGVjaWVzLCBhbmQgZ3JhemluZyBoaXN0b3J5IChibG9jayAxJjIgLS0gaGlnaCwgYmxvY2sgMyY0IC0tIGxvdykgYW5kIGF2ZXJhZ2VkLCB0aGUgc2QgYXJlIGFzIGhpZ2ggYXMgNDUuOTYhCiAgICAgICAgMS4gIHByb2NlZWRlZCB3aXRoIHRoZXNlIGhpZ2ggc2QgdG8gc2VlIHdoYXQgaGFwcGVucyAoYXNrIExhdXJlbikKCmBgYHtyfQpzaXRlLmRmIDwtIAogIGNvdmVyLmRhdC5sYWJlbHNbLCBjKDE6NywgMTg6MTkpXSAlPiUgI3N1YnNldCBjb2x1bW5zCiAgbXV0YXRlKAogICAgZ3JhemluZ19oaXN0ID0gaWZlbHNlKGJsb2NrID09IDEgfCBibG9jayA9PSAyLCAiaGlnaCIsIGlmZWxzZShibG9jayA9PSAzIHwgYmxvY2sgPT0gNCwgImxvdyIsIE5BKSkKICApICU+JSAjIHNlcGFyYXRlIGJ5IGJsb2NrIChncmF6aW5nIGludGVuc2l0aWVzKQogIGdyb3VwX2J5KG51dF90cnQsIHBwdF90cnQsIHlyLCBjb2RlNCwgZ3JhemluZ19oaXN0KSAlPiUgIyBtYWtlIGVhY2ggY29kZSB1bmlxdWUgLS0gb25lIHZhbHVlIGZvciBzcGVjaWVzIGFidW5kYW5jZSBmb3IgZWFjaCB0cnQKICBzdW1tYXJpc2UoCiAgICAjIHBjdF9jb3ZlciwKICAgIGFidW5kYW5jZSA9IG1lYW4ocGN0X2NvdmVyKQogICAgIyBzZCA9IHNkKHBjdF9jb3ZlcikKICApCgptYXRyaXgwIDwtIHNwcmVhZCgKICBzaXRlLmRmLCAKICBjb2RlNCwgCiAgYWJ1bmRhbmNlLCAKICBmaWxsID0gMCkKCiMgbWFrZSByb3duYW1lcyAtLS0tCnJvd25hbWVzKG1hdHJpeDApIDwtIHBhc3RlKG1hdHJpeDAkbnV0X3RydCwgbWF0cml4MCRwcHRfdHJ0LCBtYXRyaXgwJHlyLCBtYXRyaXgwJGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKIyBkZWxldGUgY29sdW1ucyAtLS0tIAptYXRyaXggPC0gbWF0cml4MFssIGMoNTo3OSldCgojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LmJyYXkgPC0gZGVjb3N0YW5kKG1hdHJpeCwgInRvdGFsIikKcm93bmFtZXMobWF0cml4LmJyYXkpIDwtIHJvd25hbWVzKG1hdHJpeDApCmBgYAoKIyMgUnVuIE5NRFMKClJ1bGVzIG9mIHRodW1iOgoKLSAgIFw8IDAuMDUgaXMgKipleGNlbGxlbnQqKgoKLSAgIDAuMDUtMC4xIGlzICoqZ29vZCoqCgotICAgMC4xLTAuMiBpcyAqKmZhaXIqKgoKLSAgIDAuMi0wLjMgKippcyBjYXVzZSBmb3IgY29uY2Vybi4uLioqCgotICAgXD4gMC4zICoqaXMgcG9vciwgcmFuZG9tKioKCiMjIyBBbGwgeWVhcnMKCltTdHJlc3M6XXsudW5kZXJsaW5lfSAqZmFpcioKCmBgYCAgICAgICAgIAowLjE5NjY1NTMgCmBgYAoKR3JvdXBpbmcgYnkgeWVhciBhbmQgZ3JhemluZyBoaXN0b3J5IGhhZCBtb3N0IHNpZ25pZmljYW50IGNsdXN0ZXJpbmcgc2hvd24uCgojIyMjIyBtZXRhTURTKCkKCmBgYHtyfQpubWRzLmNvbXAgPC0gbWV0YU1EUyhtYXRyaXguYnJheSwgaz0yLCB0cnltYXggPSAyNSkKbm1kcy5jb21wICMgcHJldHR5IG5vdCBncmVhdCBzdHJlc3MKc3RyZXNzcGxvdChubWRzLmNvbXApCnBsb3Qobm1kcy5jb21wLCB0eXBlPSJ0IikKCm5tZHMxIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuY29tcCwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKSAlPiUKICBtdXRhdGUobWF0cml4MFssIGMoMDo0KV0pCm5tZHMyIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuY29tcCwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc19kYXQgPC0gY2JpbmQobm1kczEsIG5tZHMyKSAlPiUKICBzZWxlY3QobnV0X3RydDpncmF6aW5nX2hpc3QsIE5NRFMxLCBOTURTMikKCmBgYAoKIyMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0LCBjb2xvciA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSArCiAgY3VzdG9tX2NvbG9ycyArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikKCmdncGxvdChubWRzX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgY29sb3IgPSBhcy5mYWN0b3IoeXIpLCBmaWxsID0gYXMuZmFjdG9yKHlyKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IFllYXIiKQoKZ2dwbG90KG5tZHNfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCBmaWxsID0gYXMuZmFjdG9yKHBwdF90cnQpLCBjb2xvciA9IGFzLmZhY3RvcihwcHRfdHJ0KSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikgKwogIGN1c3RvbV9jb2xvcnMgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgpnZ3Bsb3Qobm1kc19kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCksIGNvbG9yID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCkpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBHcmF6aW5nIEhpc3RvcnkiKQoKZ2dwbG90KG5tZHNfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBhcy5mYWN0b3IoZ3JhemluZ19oaXN0KSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGFzLmZhY3Rvcih5cikpLCBzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMSkgKwogIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoeXIpKSwgCiAgICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IEdyYXppbmcgSGlzdG9yeSAmIFllYXIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAibG93IiA9ICJjeWFuIiwKICAgICJoaWdoIiA9ICJicm93biIsCiAgIjIwMTkiID0gInNhbG1vbiIsCiAgIjIwMjAiID0gImxpbWVncmVlbiIsCiAgIjIwMjEiID0gImNvcm5mbG93ZXJibHVlIikKICApCiAgCmdncGxvdChubWRzX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgY29sb3IgPSBudXRfdHJ0LCBmaWxsID0gYXMuZmFjdG9yKHlyKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAxKSArCiAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvciA9IGFzLmZhY3RvcihudXRfdHJ0KSksCiAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgZmlsbCA9IE5BLCAgIyBNYWtlcyB0aGUgZWxsaXBzZSB0cmFuc3BhcmVudCBpbnNpZGUKICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IE51dHJpZW50IFRyZWF0bWVudCAmIFllYXIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikKCmBgYAoKIyMjIEFsbCB5ZWFycyAtIExPVyBHUkFaSU5HIE9OTFkKCltTdHJlc3M6XXsudW5kZXJsaW5lfSAqZmFpcioKCmBgYCAgICAgICAgIAowLjE4NjkwNjgKYGBgCgojIyMjIGRhdGEgd3JhbmdsaW5nCgpgYGB7cn0KIyByZWxhdGl2aXplIGRhdGEgd2l0aCBCcmF5LUN1cnRpcyBkaXNzaW1pbGFyaXR5Cm1hdHJpeC5sb3cgPC0gbWF0cml4MCAlPiUKICBmaWx0ZXIoZ3JhemluZ19oaXN0ID09ICJsb3ciKQoKcm93LmxvdyA8LSBwYXN0ZShtYXRyaXgubG93JG51dF90cnQsIG1hdHJpeC5sb3ckcHB0X3RydCwgbWF0cml4LmxvdyR5ciwgbWF0cml4LmxvdyRncmF6aW5nX2hpc3QsIHNlcCA9ICJfIikKCm1hdHJpeC5sb3cgPC0gbWF0cml4Lmxvd1ssIGMoNTo3OSldCgpyb3duYW1lcyhtYXRyaXgubG93KSA8LSByb3cubG93CgptYXRyaXguYnJheS5sb3cgPC0gZGVjb3N0YW5kKG1hdHJpeC5sb3csICJ0b3RhbCIpCmBgYAoKIyMjIyBtZXRhTURTKCkKCmBgYHtyfQpubWRzLmNvbXAubG93IDwtIG1ldGFNRFMobWF0cml4LmJyYXkubG93LCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLmNvbXAubG93ICMgcHJldHR5IG5vdCBncmVhdCBzdHJlc3MKc3RyZXNzcGxvdChubWRzLmNvbXAubG93KQpwbG90KG5tZHMuY29tcC5sb3csIHR5cGU9InQiKQoKbm1kczEgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy5jb21wLmxvdywgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKSAlPiUKICBtdXRhdGUoCiAgICBudXRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC5sb3cpLCAiXyIpLCBgW2AsIDEpLAogICAgcHB0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXgubG93KSwgIl8iKSwgYFtgLCAyKSwKICAgIHlyID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC5sb3cpLCAiXyIpLCBgW2AsIDMpLAogICAgZ3JhemluZ19oaXN0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC5sb3cpLCAiXyIpLCBgW2AsIDQpCiAgKQpubWRzMiA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLmNvbXAubG93LCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzX2xvd19kYXQgPC0gY2JpbmQobm1kczEsIG5tZHMyKSAlPiUKICBzZWxlY3QobnV0X3RydDpncmF6aW5nX2hpc3QsIE5NRFMxLCBOTURTMikKYGBgCgojIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc19sb3dfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBhcy5mYWN0b3IoeXIpLCBzaGFwZSA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgc3Ryb2tlID0gMSkgKyAKICBsYWJzKHRpdGxlID0gIjIwMTktMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IFllYXIgJiBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfbG93X2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBsYWJzKHRpdGxlID0gIjIwMTktMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IE51dHJpZW50IFRyZWF0bWVudCIpKyAKICBjdXN0b21fY29sb3JzCgoKZ2dwbG90KG5tZHNfbG93X2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDE5LTIwMjEgKExPVykgLSBHcm91cGluZyBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpIAoKIyBhZGQgeWVhciBlbGxpcHNlcyAtLS0tIApnZ3Bsb3Qobm1kc19sb3dfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoeXIpKSwgCiAgICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICIyMDE5LTIwMjEgKExPVykgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSsgCiAgY3VzdG9tX2NvbG9ycwoKCmdncGxvdChubWRzX2xvd19kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgICBzdGF0X2VsbGlwc2UoYWVzKGNvbG9yID0gYXMuZmFjdG9yKHlyKSksIAogICAgICAgICAgICAgICAgZ2VvbSA9ICJwb2x5Z29uIiwKICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICBzaXplID0gMSkgKwogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMTktMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikgCmBgYAoKIyMgTWFrZSBlYWNoIGluZGl2aWR1YWwgeWVhciBOTURTIHRvIHNlZSBpZiB0aGVyZSdzIGJldHRlciBzdHJlc3MKCiMjIyAyMDE5CgojIyMjIGRhdGEgd3JhbmdsaW5nCgpgYGB7cn0KIyByZWxhdGl2aXplIGRhdGEgd2l0aCBCcmF5LUN1cnRpcyBkaXNzaW1pbGFyaXR5Cm1hdHJpeC4yMDE5IDwtIG1hdHJpeDAgJT4lCiAgZmlsdGVyKHlyID09IDIwMTkpCgpyb3cuMjAxOSA8LSBwYXN0ZShtYXRyaXguMjAxOSRudXRfdHJ0LCBtYXRyaXguMjAxOSRwcHRfdHJ0LCBtYXRyaXguMjAxOSR5ciwgbWF0cml4LjIwMTkkZ3JhemluZ19oaXN0LCBzZXAgPSAiXyIpCgptYXRyaXguMjAxOSA8LSBtYXRyaXguMjAxOVssIGMoNTo3OSldCgpyb3duYW1lcyhtYXRyaXguMjAxOSkgPC0gcm93LjIwMTkKCm1hdHJpeC5icmF5LjIwMTkgPC0gZGVjb3N0YW5kKG1hdHJpeC4yMDE5LCAidG90YWwiKQpgYGAKCiMjIyMgbm1kcyAyMDE5CgpbU3RyZXNzOl17LnVuZGVybGluZX0gKkV4Y2VsbGVudCoKCmBgYCAgICAgICAgIAowLjA1NjAxNzgKYGBgCgojIyMjIyBtZXRhTURTKCkKCmBgYHtyfQpubWRzLjIwMTkgPC0gbWV0YU1EUyhtYXRyaXguYnJheS4yMDE5LCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMTkgIyBwcmV0dHkgbm90IGdyZWF0IHN0cmVzcwpzdHJlc3NwbG90KG5tZHMuMjAxOSkKcGxvdChubWRzLjIwMTksIHR5cGU9InQiKQoKbm1kczEuMjAxOSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMTksIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKAogICAgbnV0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAxOSksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDE5KSwgIl8iKSwgYFtgLCAyKSwKICAgIHlyID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDE5KSwgIl8iKSwgYFtgLCAzKSwKICAgIGdyYXppbmdfaGlzdCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAxOSksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMTkgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDE5LCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMTlfZGF0IDwtIGNiaW5kKG5tZHMxLjIwMTksIG5tZHMyLjIwMTkpICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc18yMDE5X2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gZ3JhemluZ19oaXN0LCBzaGFwZSA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgc3Ryb2tlID0gMSkgKyAKICBsYWJzKHRpdGxlID0gIjIwMTkgLSBHcm91cGluZyBieSBHcmF6aW5nIEhpc3RvcnkgJiBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAxOV9kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgbGFicyh0aXRsZSA9ICIyMDE5IC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikrIAogIGN1c3RvbV9jb2xvcnMKCgpnZ3Bsb3Qobm1kc18yMDE5X2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDE5IC0gR3JvdXBpbmcgYnkgUHJlY2lwaXRhdGlvbiBUcmVhdG1lbnQiKSAKCmBgYAoKYGBgICAgICAgICAgCmBgYAoKIyMjIDIwMjAKCiMjIyMgZGF0YSB3cmFuZ2xpbmcKCmBgYHtyfQojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LjIwMjAgPC0gbWF0cml4MCAlPiUKICBmaWx0ZXIoeXIgPT0gMjAyMCkKCnJvdy4yMDIwIDwtIHBhc3RlKG1hdHJpeC4yMDIwJG51dF90cnQsIG1hdHJpeC4yMDIwJHBwdF90cnQsIG1hdHJpeC4yMDIwJHlyLCBtYXRyaXguMjAyMCRncmF6aW5nX2hpc3QsIHNlcCA9ICJfIikKCm1hdHJpeC4yMDIwIDwtIG1hdHJpeC4yMDIwWywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC4yMDIwKSA8LSByb3cuMjAyMAoKbWF0cml4LmJyYXkuMjAyMCA8LSBkZWNvc3RhbmQobWF0cml4LjIwMjAsICJ0b3RhbCIpCmBgYAoKIyMjIyBubWRzIDIwMjAKCltTdHJlc3M6XXsudW5kZXJsaW5lfSAqZmFpcioKCmBgYCAgICAgICAgIAowLjE1MjI0OTUKYGBgCgojIyMjIyBtZXRhTURTKCkKCmBgYHtyfQpubWRzLjIwMjAgPC0gbWV0YU1EUyhtYXRyaXguYnJheS4yMDIwLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjAKc3RyZXNzcGxvdChubWRzLjIwMjApCnBsb3Qobm1kcy4yMDIwLCB0eXBlPSJ0IikKCm5tZHMxLjIwMjAgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIwLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjApLCAiXyIpLCBgW2AsIDEpLAogICAgcHB0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMCksICJfIiksIGBbYCwgMiksCiAgICB5ciA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMCksICJfIiksIGBbYCwgMyksCiAgICBncmF6aW5nX2hpc3QgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjApLCAiXyIpLCBgW2AsIDQpCiAgKQpubWRzMi4yMDIwIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMCwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc18yMDIwX2RhdCA8LSBjYmluZChubWRzMS4yMDIwLCBubWRzMi4yMDIwKSAlPiUKICBzZWxlY3QobnV0X3RydDpncmF6aW5nX2hpc3QsIE5NRFMxLCBOTURTMikKYGBgCgojIyMjIyBwbG90CgpgYGB7cn0KZ2dwbG90KG5tZHNfMjAyMF9kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBjb2xvciA9IGdyYXppbmdfaGlzdCwgc2hhcGUgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDQsIHN0cm9rZSA9IDEpICsgCiAgbGFicyh0aXRsZSA9ICIyMDIwIC0gR3JvdXBpbmcgYnkgR3JhemluZyBIaXN0b3J5ICYgTnV0cmllbnQgVHJlYXRtZW50IikgCgpnZ3Bsb3Qobm1kc18yMDIwX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIwIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikKCmdncGxvdChubWRzXzIwMjBfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjAgLSBHcm91cGluZyBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpCmBgYAoKIyMjIDIwMjEKCiMjIyMgZGF0YSB3cmFuZ2xpbmcKCmBgYHtyfQojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LjIwMjEgPC0gbWF0cml4MCAlPiUKICBmaWx0ZXIoeXIgPT0gMjAyMSkKCnJvdy4yMDIxIDwtIHBhc3RlKG1hdHJpeC4yMDIxJG51dF90cnQsIG1hdHJpeC4yMDIxJHBwdF90cnQsIG1hdHJpeC4yMDIxJHlyLCBtYXRyaXguMjAyMSRncmF6aW5nX2hpc3QsIHNlcCA9ICJfIikKCm1hdHJpeC4yMDIxIDwtIG1hdHJpeC4yMDIxWywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC4yMDIxKSA8LSByb3cuMjAyMQoKbWF0cml4LmJyYXkuMjAyMSA8LSBkZWNvc3RhbmQobWF0cml4LjIwMjEsICJ0b3RhbCIpCmBgYAoKIyMjIyBubWRzIDIwMjEKCltTdHJlc3M6XXsudW5kZXJsaW5lfSAqZmFpcioKCmBgYCAgICAgICAgIAowLjEyMzA4MzEKYGBgCgojIyMjIyBtZXRhTURTKCkKCmBgYHtyfQpubWRzLjIwMjEgPC0gbWV0YU1EUyhtYXRyaXguYnJheS4yMDIxLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjEKc3RyZXNzcGxvdChubWRzLjIwMjEpCnBsb3Qobm1kcy4yMDIxLCB0eXBlPSJ0IikKCm5tZHMxLjIwMjEgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEpLCAiXyIpLCBgW2AsIDEpLAogICAgcHB0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMSksICJfIiksIGBbYCwgMiksCiAgICB5ciA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMSksICJfIiksIGBbYCwgMyksCiAgICBncmF6aW5nX2hpc3QgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEpLCAiXyIpLCBgW2AsIDQpCiAgKQpubWRzMi4yMDIxIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMSwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc18yMDIxX2RhdCA8LSBjYmluZChubWRzMS4yMDIxLCBubWRzMi4yMDIxKSAlPiUKICBzZWxlY3QobnV0X3RydDpncmF6aW5nX2hpc3QsIE5NRFMxLCBOTURTMikKYGBgCgojIyMjIyBwbG90CgpgYGB7cn0KZ2dwbG90KG5tZHNfMjAyMV9kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBjb2xvciA9IGdyYXppbmdfaGlzdCwgc2hhcGUgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKwogIGxhYnModGl0bGUgPSAiMjAyMSAtIEdyb3VwaW5nIGJ5IEdyYXppbmcgSGlzdG9yeSAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDIxX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikKCmdncGxvdChubWRzXzIwMjFfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgLSBHcm91cGluZyBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpCmBgYAoKIyMgTWFrZSBzcGVjaWVzIHggdHJhaXQgbWF0cml4CgpHcmVlbmhvdXNlIHRyYWl0cwoKLSAgIGhlaWdodCwgbGVhZiBkcnkgbWF0dGVyIGNvbnRlbnQsIHNwZWNpZmljIGxlYWYgYXJlYSwgcm9vdCBtYXNzIGZyYWN0aW9uLCByZWxhdGl2ZSBncm93dGggcmF0ZSwgY29hcnNlIHJvb3QgZGlhbWV0ZXIsIHJvb3QgZGVuc2l0eSwgc3BlY2lmaWMgcm9vdCBsZW5ndGggb2YgZmluZSByb290cywgc3BlY2lmaWMgcm9vdCBsZW5ndGggb2YgY29hcnNlIHJvb3RzCgpGaWVsZCB0cmFpdHMKCi0gICBoZWlnaHQsIGxlYWYgZHJ5IG1hdHRlciBjb250ZW50LCBzcGVjaWZpYyBsZWFmIGFyZWEsIHNlZWQgbWFzcywgbGVhZiBDLCBsZWFmIE4KCmBgYHtyfQojIHJlYWQgaW4gdHJhaXQgZGF0YQoKIyBzdWJzZXQgdHJhaXQgZGF0YSB0byBtYXRjaCBjb21wIGRhdGEKCiMgc2V0IG1hdGNoaW5nIHJvdyBuYW1lcwoKCmBgYAoKIyMjIAo=